//
//  SampleHandler.m
//  recoder
//
//  Created by szblsx2 on 2020/3/25.
//  Copyright © 2020 szblsx. All rights reserved.
//


#import "SampleHandler.h"

#import "NTESYUVConverter.h"
#import "NTESI420Frame.h"
#import "GCDAsyncSocket.h"
#import "NTESSocketPacket.h"
#import "NTESTPCircularBuffer.h"

@interface SampleHandler ()<GCDAsyncSocketDelegate>

//裁剪比例
@property (nonatomic, assign) CGFloat cropRate;
//分辨率
@property (nonatomic, assign) CGSize  targetSize;
//方向
@property (nonatomic, assign) NTESVideoPackOrientation orientation;

@property (nonatomic, assign) BOOL connected;
@property (nonatomic, assign) NSUInteger frameCount;
@property (nonatomic, strong) GCDAsyncSocket *clinetSocket;

@end

@implementation SampleHandler

- (void)dealloc
{
    _connected = NO;
    if (_clinetSocket) {
        [_clinetSocket disconnect];
        _clinetSocket = nil;
    }
}

- (instancetype)init
{
    if(self = [super init]) {
        _targetSize = CGSizeMake(540, 960);
//        _targetSize = CGSizeMake(720, 1280);
        _cropRate = 9.0/16;
        _orientation = NTESVideoPackOrientationPortrait;
    }
    return self;
}

- (void)broadcastStartedWithSetupInfo:(NSDictionary<NSString *,NSObject *> *)setupInfo
{
    NSLog(@"开启录屏");
    [self sendNotificationForMessageWithIdentifier:kRecoderBroadcastStarted userInfo:setupInfo];
    
    [self setupSocket];
}

- (void)broadcastPaused
{
    NSLog(@"录屏暂停");
    [self sendNotificationForMessageWithIdentifier:kRecoderBroadcastPaused userInfo:nil];
}

- (void)broadcastResumed
{
    NSLog(@"录屏恢复");
    [self sendNotificationForMessageWithIdentifier:kRecoderBroadcastResumed userInfo:nil];
}

- (void)broadcastFinished
{
    NSLog(@"录屏完成");
    [self sendNotificationForMessageWithIdentifier:kRecoderBroadcastFinished userInfo:nil];
}

- (void)finishBroadcastWithError:(NSError *)error
{
    NSLog(@"录制出错完成 %@",error);
    
}

- (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer withType:(RPSampleBufferType)sampleBufferType {
    switch (sampleBufferType) {
        case RPSampleBufferTypeVideo:
            if (self.connected) {
                [self sendVideoBufferToHostApp:sampleBuffer];
            }
            break;
        case RPSampleBufferTypeAudioApp:
            // Handle audio sample buffer for app audio
            break;
        case RPSampleBufferTypeAudioMic:
            // Handle audio sample buffer for mic audio
            break;
            
        default:
            break;
    }
}

#pragma mark - Socket

- (void)setupSocket
{
    self.clinetSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_queue_create("com.blsx.edu.rp.client", DISPATCH_QUEUE_SERIAL)];
    NSError *error;
    [self.clinetSocket connectToHost:@"127.0.0.1" onPort:9898 error:&error];
    [self.clinetSocket readDataWithTimeout:-1 tag:0];
    
    if (error) {
        [self sendNotificationForMessageWithIdentifier:kRecoderSocketConnectFaild userInfo:nil];
    }
}

#pragma mark - GCDAsyncSocketDelegate

- (void)socket:(GCDAsyncSocket *)sock didConnectToUrl:(NSURL *)url
{
    [self.clinetSocket readDataWithTimeout:-1 tag:0];
}

- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port
{
    [self.clinetSocket readDataWithTimeout:-1 tag:0];
    self.connected = YES;
}

- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err
{
    self.connected = NO;
    [self.clinetSocket disconnect];
    self.clinetSocket = nil;
    [self setupSocket];
}


#pragma mark - Method

/**发送视频帧*/
- (void)sendVideoBufferToHostApp:(CMSampleBufferRef)sampleBuffer
{
    if (!self.clinetSocket){
        return;
    }
    
    CFRetain(sampleBuffer);
    
    dispatch_async(dispatch_queue_create("com.blsx.edu.rp.videoprocess", DISPATCH_QUEUE_SERIAL), ^{ // queue optimal
        
        @autoreleasepool {
            if (self.frameCount > 1000){
                CFRelease(sampleBuffer);
                return;
            }
            self.frameCount ++ ;
            
            CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
            
            NTESI420Frame *videoFrame = nil;
            videoFrame = [NTESYUVConverter pixelBufferToI420:pixelBuffer
                                                    withCrop:self.cropRate
                                                  targetSize:self.targetSize
                                              andOrientation:self.orientation];
            CFRelease(sampleBuffer);
            
            if (videoFrame){
                NSData *rawData = [videoFrame bytes];
                NSData *headerData = [NTESSocketPacket packetWithBuffer:rawData];
                [self.clinetSocket writeData:headerData withTimeout:5 tag:0];
                [self.clinetSocket writeData:rawData withTimeout:5 tag:0];
                
            }
            self.frameCount --;
        };
    });
}

- (NSData *)packetWithBuffer:(NSData *)rawData
{
    NSMutableData *mutableData = [NSMutableData data];
    
    @autoreleasepool {
        if (rawData.length == 0){
            return NULL;
        }
        size_t size = rawData.length;
        void *data = malloc(sizeof(NTESPacketHead));
        NTESPacketHead *head = (NTESPacketHead *)malloc(sizeof(NTESPacketHead));
        head->version = 1;
        head->command_id = 0;
        head->service_id = 0;
        head->serial_id = 0;
        head->data_len = (uint32_t)size;
        
        size_t headSize = sizeof(NTESPacketHead);
        memcpy(data, head, headSize);
        NSData *headData = [NSData dataWithBytes:data length:headSize];
        [mutableData appendData:headData];
        [mutableData appendData:rawData];
        
        free(data);
        free(head);
    }
    return [mutableData copy];
}

/**发送通知到宿主app*/
- (void)sendNotificationForMessageWithIdentifier:(nullable NSString *)identifier userInfo:(NSDictionary *)info
{
    CFNotificationCenterRef const center = CFNotificationCenterGetDarwinNotifyCenter();
    CFDictionaryRef userInfo = (__bridge CFDictionaryRef)info;
    BOOL const deliverImmediately = YES;
    CFStringRef identifierRef = (__bridge CFStringRef)identifier;
    CFNotificationCenterPostNotification(center, identifierRef, NULL, userInfo, deliverImmediately);
}



@end
